package eci

import (
	"eci-forward/pkg/config"
	"eci-forward/pkg/logs"
	"fmt"
	"strings"

	openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
	eci20180808 "github.com/alibabacloud-go/eci-20180808/v3/client"
	"github.com/alibabacloud-go/tea/tea"
	"github.com/google/uuid"
	"go.uber.org/zap"

	util "github.com/alibabacloud-go/tea-utils/v2/service"
)

// var eciClient *eci20180808.Client
var eciClients = make(map[string]*eci20180808.Client)

func getClient(departmentName string) (*eci20180808.Client, error) {
	client, ok := eciClients[departmentName]
	if ok {
		return client, nil
	}

	eciClient, err := CreateClient(
		tea.String(config.GetECIConfig(departmentName).AccessKeyId),
		tea.String(config.GetECIConfig(departmentName).AccessKeySecret),
		tea.String(config.GetECIConfig(departmentName).Endpoint),
	)
	if err != nil {
		return nil, err
	}
	eciClients[departmentName] = eciClient
	return eciClient, nil
}

func CreateClient(accessKeyId, accessKeySecret, endpoint *string) (client *eci20180808.Client, err error) {
	if accessKeyId == nil || accessKeySecret == nil || endpoint == nil {
		return nil, fmt.Errorf("accessKeyId, accessKeySecret, endpoint can not be nil")
	}
	openapiConfig := &openapi.Config{
		AccessKeyId:     accessKeyId,
		AccessKeySecret: accessKeySecret,
		Endpoint:        endpoint,
	}
	client, err = eci20180808.NewClient(openapiConfig)
	return client, err
}

// 创建随机imagecachename
func CreateRandomImageCacheName(departmentName string) (string, error) {
	// uuid from timestamp
	u1, err := uuid.NewUUID()
	if err != nil {
		return "", err
	}
	return config.GetECIConfig(departmentName).ImageCacheNamePrefix + u1.String(), nil
}

func CreateImageCache(departmentName string, images *[]string, optionalParams ...int32) (string, error) {
	var imageCacheSize int32
	var retentionDays int32

	// 检查是否传递了ImageCacheSize参数
	if len(optionalParams) > 0 {
		imageCacheSize = optionalParams[0]
	} else {
		imageCacheSize = config.GetECIConfig(departmentName).ImageCacheSize
	}

	// 检查是否传递了RetentionDays参数
	if len(optionalParams) > 1 {
		retentionDays = optionalParams[1]
	} else {
		retentionDays = config.GetECIConfig(departmentName).RetentionDays
	}

	client, err := getClient(departmentName)
	if err != nil {
		return "", err
	}

	imageCacheName, err := CreateRandomImageCacheName(departmentName)
	if err != nil {
		return "", err
	}
	logs.Logger.Info("Begin to create image cache", zap.String("imageCacheName", imageCacheName), zap.Any("images", images))
	createImageCachesRequest := &eci20180808.CreateImageCacheRequest{
		RegionId:            tea.String(config.GetECIConfig(departmentName).RegionId),
		SecurityGroupId:     tea.String(config.GetECIConfig(departmentName).SecurityGroupId),
		VSwitchId:           tea.String(config.GetECIConfig(departmentName).VSwitchId),
		ImageCacheName:      tea.String(imageCacheName),
		Image:               tea.StringSlice(*images),
		ImageCacheSize:      tea.Int32(imageCacheSize),
		AutoMatchImageCache: tea.Bool(config.GetECIConfig(departmentName).AutoMatchImageCache),
		RetentionDays:       tea.Int32(retentionDays),
	}

	tryErr := func() (e error) {
		defer func() {
			if r := tea.Recover(recover()); r != nil {
				e = r
			}
		}()

		logs.Logger.Info("CreateImageCache request", zap.String("imageCacheName", imageCacheName), zap.Any("createImageCachesRequest", createImageCachesRequest))
		fmt.Println(createImageCachesRequest)
		res, err := client.CreateImageCache(createImageCachesRequest)
		if err != nil {
			return err
		}

		logs.Logger.Info("CreateImageCache res", zap.String("imageCacheName", imageCacheName), zap.Any("res", res.GoString()))
		fmt.Println(res)
		return nil
	}()

	if tryErr != nil {
		var error = &tea.SDKError{}
		if _t, ok := tryErr.(*tea.SDKError); ok {
			error = _t
		} else {
			error.Message = tea.String(tryErr.Error())
		}
		// 如有需要，请打印 error
		msg, err := util.AssertAsString(error.Message)
		logs.Logger.Error(*msg)
		if err != nil {
			return "", err
		}
	}
	return imageCacheName, nil
}

func DescribeImageCachesWithImageCacheName(departmentName string, ImageCacheName string) (*eci20180808.DescribeImageCachesResponse, error) {
	client, err := getClient(departmentName)
	if err != nil {
		return &eci20180808.DescribeImageCachesResponse{}, err
	}

	describeImageCachesRequest := &eci20180808.DescribeImageCachesRequest{
		RegionId:       tea.String(config.GetECIConfig(departmentName).RegionId),
		ImageCacheName: tea.String(ImageCacheName),
	}

	res, tryErr := func() (res *eci20180808.DescribeImageCachesResponse, e error) {
		defer func() {
			if r := tea.Recover(recover()); r != nil {
				e = r
			}
		}()

		logs.Logger.Info("DescribeImageCaches request", zap.String("imageCacheName", ImageCacheName), zap.Any("describeImageCachesRequest", describeImageCachesRequest))
		fmt.Println(describeImageCachesRequest)
		res, err := client.DescribeImageCaches(describeImageCachesRequest)
		if err != nil {
			return &eci20180808.DescribeImageCachesResponse{}, err
		}

		logs.Logger.Info("DescribeImageCaches res", zap.String("imageCacheName", ImageCacheName), zap.Any("res", res.GoString()))
		fmt.Println(res)
		return res, nil
	}()

	if tryErr != nil {
		var error = &tea.SDKError{}
		if _t, ok := tryErr.(*tea.SDKError); ok {
			error = _t
		} else {
			error.Message = tea.String(tryErr.Error())
		}
		// 如有需要，请打印 error
		msg, err := util.AssertAsString(error.Message)
		logs.Logger.Error(*msg)
		if err != nil {
			return &eci20180808.DescribeImageCachesResponse{}, err
		}
	}
	return res, nil
}
func CheckIfHitImageCachesWithMatchImage(departmentName string, MatchImage []string) (string, error) {
	res, err := DescribeImageCachesWithMatchImage(departmentName, MatchImage)
	if err != nil {
		logs.Logger.Error("failed to describe image caches with match image", zap.Error(err))
		return "", err
	}
	if len(res.Body.ImageCaches) == 0 {
		logs.Logger.Info("no image caches found")
		return "", fmt.Errorf("no image caches found")
	} else {
		hit := CheckIfHitCache(MatchImage, res.Body.ImageCaches[0].Images)
		if hit {
			logs.Logger.Info("hit cache", zap.Any("image_cache_name", res.Body.ImageCaches[0].ImageCacheName))
			return *res.Body.ImageCaches[0].ImageCacheName, nil
		}
		return "", fmt.Errorf("no image caches found")
	}
}
func DescribeImageCachesWithMatchImage(departmentName string, MatchImage []string) (*eci20180808.DescribeImageCachesResponse, error) {
	client, err := getClient(departmentName)
	if err != nil {
		return &eci20180808.DescribeImageCachesResponse{}, err
	}
	pointerMatchImage := tea.StringSlice(MatchImage)

	describeImageCachesRequest := &eci20180808.DescribeImageCachesRequest{
		RegionId:   tea.String(config.GetECIConfig(departmentName).RegionId),
		Limit:      tea.Int32(1),
		MatchImage: pointerMatchImage,
	}

	res, tryErr := func() (res *eci20180808.DescribeImageCachesResponse, e error) {
		defer func() {
			if r := tea.Recover(recover()); r != nil {
				e = r
			}
		}()

		fmt.Println("DescribeImageCaches request", zap.Any("MatchImage", MatchImage), zap.Any("describeImageCachesRequest", describeImageCachesRequest))
		res, err := client.DescribeImageCaches(describeImageCachesRequest)
		if err != nil {
			return &eci20180808.DescribeImageCachesResponse{}, err
		}

		fmt.Println("DescribeImageCaches res", zap.Any("MatchImage", MatchImage), zap.Any("res", res.GoString()))
		return res, nil
	}()

	if tryErr != nil {
		var error = &tea.SDKError{}
		if _t, ok := tryErr.(*tea.SDKError); ok {
			error = _t
		} else {
			error.Message = tea.String(tryErr.Error())
		}
		// 如有需要，请打印 error
		msg, err := util.AssertAsString(error.Message)
		fmt.Println(*msg)
		if err != nil {
			return &eci20180808.DescribeImageCachesResponse{}, err
		}
	}

	return res, nil
}
func countElements(slice []*string) map[string]int {
	counts := make(map[string]int)
	for _, s := range slice {
		counts[*s]++
	}
	return counts
}

func slicesEqualIgnoreOrder(slice1, slice2 []*string) bool {
	if len(slice1) != len(slice2) {
		return false
	}

	return compareMaps(countElements(slice1), countElements(slice2))
}
func compareMaps(map1, map2 map[string]int) bool {
	if len(map1) != len(map2) {
		return false
	}

	for k, v := range map1 {
		if map2[k] != v {
			return false
		}
	}

	return true
}

func CheckIfHitCache(paramImageList []string, resImageList []*string) bool {
	p := strings.Split(paramImageList[0], ",")

	return slicesEqualIgnoreOrder(tea.StringSlice(p), resImageList)
}

func DescribeAvailableResource(departmentName, Category, Value string) (*eci20180808.DescribeAvailableResourceResponse, error) {
	client, err := getClient(departmentName)
	if err != nil {
		return &eci20180808.DescribeAvailableResourceResponse{}, err
	}

	describeAvailableResourceRequestDestinationResource := &eci20180808.DescribeAvailableResourceRequestDestinationResource{
		Category: tea.String(Category),
		Value:    tea.String(Value),
	}

	describeAvailableResourceRequest := &eci20180808.DescribeAvailableResourceRequest{
		RegionId:            tea.String(config.GetECIConfig(departmentName).RegionId),
		DestinationResource: describeAvailableResourceRequestDestinationResource,
	}

	res, tryErr := func() (res *eci20180808.DescribeAvailableResourceResponse, e error) {
		defer func() {
			if r := tea.Recover(recover()); r != nil {
				e = r
			}
		}()

		logs.Logger.Info("DescribeAvailableResource request", zap.String("Category", Category), zap.Any("Value", Value))
		res, err := client.DescribeAvailableResource(describeAvailableResourceRequest)
		if err != nil {
			return &eci20180808.DescribeAvailableResourceResponse{}, err
		}
		return res, nil
	}()

	if tryErr != nil {
		var error = &tea.SDKError{}
		if _t, ok := tryErr.(*tea.SDKError); ok {
			error = _t
		} else {
			error.Message = tea.String(tryErr.Error())
		}
		// 如有需要，请打印 error
		msg, err := util.AssertAsString(error.Message)
		logs.Logger.Error(*msg)
		if err != nil {
			return &eci20180808.DescribeAvailableResourceResponse{}, err
		}
	}
	return res, nil
}
